当前位置: 首页 > news >正文

游戏中的设计模式及杂项

概述

如果要做以下游戏功能会用到哪些设计模式。比如创建一个人物角色,这个角色可以装备刀,然后角色可以用刀砍怪物,造成流血。
对于这个游戏功能,可以使用以下设计模式:

  1. 工厂模式(Factory Pattern):用于创建人物角色和刀的实例。可以抽象出一个人物工厂类和刀工厂类来统一管理对象的创建过程。

  2. 装饰者模式(Decorator Pattern):用于装备刀。可以将刀作为一个装饰者,动态地给人物增加属性和行为。

  3. 策略模式(Strategy Pattern):用于刀砍怪物。可以定义一个攻击策略接口,不同的刀可以实现该接口以达到不同的攻击效果。

  4. 观察者模式(Observer Pattern):用于观察流血状态。可以将怪物作为被观察者,人物作为观察者,当人物攻击时会通知怪物更新自己的状态,并更新人物的属性。

  5. 状态模式(State Pattern):用于表现不同的状态。可以定义不同的状态(如待机、移动、攻击等),并将刀砍怪物作为一个具体的状态。

  6. 命令模式(Command Pattern):用于将攻击命令封装成对象。可以将攻击命令封装成一个具体的命令对象,然后传递给人物或者其他对象进行调用。

如果你要使用Unity实现上述功能,主要的流程可能包括以下几个步骤:

  1. 创建游戏对象:在Unity中创建游戏对象,如人物、怪物等,并设置它们的属性和初始状态。

  2. 创建刀的预制件:将刀的模型、贴图等资源打包成一个预制件,以便在游戏中使用。

  3. 实例化刀:使用工厂模式,在游戏运行时动态创建刀的实例,并将它们挂载到人物身上。

  4. 装备刀:使用装饰者模式,在游戏运行时动态地给人物增加刀的属性和行为。

  5. 切换攻击策略:使用策略模式,在游戏中根据人物当前的状态选择不同的攻击策略(即不同的刀)。

  6. 观察流血状态:使用观察者模式,在游戏中让怪物作为被观察者,人物作为观察者,当人物攻击时会通知怪物更新自己的状态,并更新人物的属性。

  7. 更新状态:使用状态模式,根据人物当前的状态更新其动画、移动、攻击等行为。

  8. 执行攻击命令:使用命令模式,将攻击命令封装成对象,然后传递给人物进行调用,同时更新怪物的状态。

  9. 碰撞检测:使用Unity提供的物理引擎,在游戏中实现人物与怪物之间的碰撞检测,检测到碰撞后执行相应的操作,如扣除怪物血量、播放受伤动画等。

以上是实现这个游戏功能的一些基本步骤。在具体实现过程中,还需要涉及到很多细节问题,如如何控制动画的播放、如何处理输入事件等,需要根据具体情况进一步考虑和实现。

装饰者模式

装饰者模式(Decorator Pattern):用于装备刀。可以将刀作为一个装饰者,动态地给人物增加属性和行为。

你说得对,角色装备武器的行为应该由角色来管理,而不是由武器直接管理。我们可以调整设计,使角色能够装备武器,并且通过装饰者模式动态地增加属性和行为。

下面是改进后的代码示例:

1. 定义角色接口和基本实现

首先,定义角色接口和基本角色实现类。

// 角色接口
public interface Character {void display();int getAttackPower();void equip(Weapon weapon);
}// 基本角色实现
public class BasicCharacter implements Character {private String name;private int attackPower;public BasicCharacter(String name, int attackPower) {this.name = name;this.attackPower = attackPower;}@Overridepublic void display() {System.out.println(name + " 准备战斗!");}@Overridepublic int getAttackPower() {return attackPower;}@Overridepublic void equip(Weapon weapon) {throw new UnsupportedOperationException("基础角色不能直接装备武器");}
}

2. 定义武器接口和具体实现

定义一个武器接口和具体的武器实现类。

// 武器接口
public interface Weapon {void display();int getAdditionalAttackPower();default int getAdditionalMagicPower() {return 0; // 默认没有魔法值}
}// 普通刀
public class CommonKnife implements Weapon {private int additionalAttackPower;public CommonKnife(int additionalAttackPower) {this.additionalAttackPower = additionalAttackPower;}@Overridepublic void display() {System.out.println("装备了普通刀!");}@Overridepublic int getAdditionalAttackPower() {return additionalAttackPower;}
}// 长剑
public class LongSword implements Weapon {private int additionalAttackPower;public LongSword(int additionalAttackPower) {this.additionalAttackPower = additionalAttackPower;}@Overridepublic void display() {System.out.println("装备了长剑!");}@Overridepublic int getAdditionalAttackPower() {return additionalAttackPower;}
}// 魔法刀
public class MagicKnife implements Weapon {private int additionalAttackPower;private int additionalMagicPower;public MagicKnife(int additionalAttackPower, int additionalMagicPower) {this.additionalAttackPower = additionalAttackPower;this.additionalMagicPower = additionalMagicPower;}@Overridepublic void display() {System.out.println("装备了魔法刀!");}@Overridepublic int getAdditionalAttackPower() {return additionalAttackPower;}@Overridepublic int getAdditionalMagicPower() {return additionalMagicPower;}
}

3. 定义装饰者基类

定义一个装饰者基类,它包含了对武器的支持。

// 装饰者基类
public abstract class CharacterDecorator implements Character {protected Character character;protected Weapon weapon;public CharacterDecorator(Character character) {this.character = character;}@Overridepublic void display() {character.display();if (weapon != null) {weapon.display();}}@Overridepublic int getAttackPower() {if (weapon != null) {return character.getAttackPower() + weapon.getAdditionalAttackPower();}return character.getAttackPower();}@Overridepublic int getMagicPower() {if (weapon instanceof MagicKnife) {return character.getMagicPower() + ((MagicKnife) weapon).getAdditionalMagicPower();}return character.getMagicPower();}@Overridepublic void equip(Weapon weapon) {this.weapon = weapon;}
}

4. 更新角色接口和基本实现

为了支持魔法刀的额外属性,我们需要更新角色接口和基本实现类。

更新角色接口
public interface Character {void display();int getAttackPower();int getMagicPower();void equip(Weapon weapon);
}
更新基本角色实现
public class BasicCharacter implements Character {private String name;private int attackPower;public BasicCharacter(String name, int attackPower) {this.name = name;this.attackPower = attackPower;}@Overridepublic void display() {System.out.println(name + " 准备战斗!");}@Overridepublic int getAttackPower() {return attackPower;}@Overridepublic int getMagicPower() {return 0; // 基本角色默认没有魔法值}@Overridepublic void equip(Weapon weapon) {throw new UnsupportedOperationException("基础角色不能直接装备武器");}
}

5. 更新测试代码

现在我们可以测试不同类型的刀装备效果。

public class DecoratorPatternDemo {public static void main(String[] args) {// 创建一个基本角色Character basicCharacter = new BasicCharacter("勇士", 100);// 创建装饰者角色Character decoratedCharacter = new CharacterDecorator(basicCharacter) {};// 显示基本信息decoratedCharacter.display();System.out.println("攻击力: " + decoratedCharacter.getAttackPower());System.out.println("魔法值: " + decoratedCharacter.getMagicPower());// 装备普通刀Weapon commonKnife = new CommonKnife(50);decoratedCharacter.equip(commonKnife);decoratedCharacter.display();System.out.println("攻击力: " + decoratedCharacter.getAttackPower());System.out.println("魔法值: " + decoratedCharacter.getMagicPower());// 装备长剑Weapon longSword = new LongSword(70);decoratedCharacter.equip(longSword);decoratedCharacter.display();System.out.println("攻击力: " + decoratedCharacter.getAttackPower());System.out.println("魔法值: " + decoratedCharacter.getMagicPower());// 装备魔法刀Weapon magicKnife = new MagicKnife(100, 50);decoratedCharacter.equip(magicKnife);decoratedCharacter.display();System.out.println("攻击力: " + decoratedCharacter.getAttackPower());System.out.println("魔法值: " + decoratedCharacter.getMagicPower());}
}

运行结果

运行上述代码,输出将会是:

勇士 准备战斗!
攻击力: 100
魔法值: 0
勇士 准备战斗!
装备了普通刀!
攻击力: 150
魔法值: 0
勇士 准备战斗!
装备了长剑!
攻击力: 170
魔法值: 0
勇士 准备战斗!
装备了魔法刀!
攻击力: 200
魔法值: 50

解释

  1. 基本角色BasicCharacter 类实现了 Character 接口,提供了一个基本的角色实现。基础角色不能直接装备武器。
  2. 武器接口和具体实现:定义了 Weapon 接口和具体的武器实现类 CommonKnifeLongSwordMagicKnife
  3. 装饰者基类CharacterDecorator 类包含了一个对 Character 的引用和一个对 Weapon 的引用,可以在运行时动态地添加武器。
  4. 测试代码:创建一个基本角色,然后通过装饰者模式为其装备不同类型的刀,最终显示装备后的角色信息。

通过这种方式,角色可以动态地装备武器,并且武器的属性会在角色的属性上进行叠加。这样设计更加符合实际的游戏逻辑。

工厂+策略模式

在面向对象设计中,使用工厂方法(Factory Method)模式来创建不同类型的对象是一个常见的做法,它可以使得代码更加灵活和可扩展。而策略模式(Strategy Pattern)则用于定义一系列算法,并将每个算法封装起来,使它们可以互相替换。结合这两种模式,我们可以创建一个系统来处理游戏中不同类型的刀及其独特的攻击方式。

设计思路

1. 工厂方法模式

首先,我们定义一个Knife接口或抽象类,它代表所有刀的基本属性和行为。接着,为每一种特定类型的刀创建具体的类,这些类都实现了Knife接口或继承自Knife抽象类。

public abstract class Knife {public abstract void attack(); // 定义攻击行为
}public class Sword extends Knife {@Overridepublic void attack() {System.out.println("挥剑攻击!");}
}public class Dagger extends Knife {@Overridepublic void attack() {System.out.println("匕首快速刺击!");}
}

接下来,定义一个工厂类来根据需求创建不同类型的刀。

public class KnifeFactory {public static Knife createKnife(String type) {if ("sword".equals(type)) {return new Sword();} else if ("dagger".equals(type)) {return new Dagger();}throw new IllegalArgumentException("未知的刀类型");}
}
2. 策略模式

为了使每种刀有不同的攻击方式,我们可以引入策略模式。首先定义一个AttackStrategy接口,然后为每种攻击方式创建一个具体实现类。

public interface AttackStrategy {void performAttack();
}public class SlashAttack implements AttackStrategy {@Overridepublic void performAttack() {System.out.println("进行斩击...");}
}public class StabAttack implements AttackStrategy {@Overridepublic void performAttack() {System.out.println("进行刺击...");}
}

然后修改Knife类,使其可以接受一个AttackStrategy实例作为其攻击方式。

public abstract class Knife {protected AttackStrategy attackStrategy;public void setAttackStrategy(AttackStrategy strategy) {this.attackStrategy = strategy;}public void attack() {if (attackStrategy != null) {attackStrategy.performAttack();} else {System.out.println("没有设置攻击策略!");}}
}

这样,每当我们创建一把新刀时,都可以为其设置一个具体的攻击策略。

示例应用

假设我们想创建一把剑并设置它的攻击方式为斩击:

public static void main(String[] args) {Knife sword = KnifeFactory.createKnife("sword");sword.setAttackStrategy(new SlashAttack());sword.attack(); // 输出: 进行斩击...
}

同样的,如果要创建一把匕首并设置其攻击方式为刺击:

Knife dagger = KnifeFactory.createKnife("dagger");
dagger.setAttackStrategy(new StabAttack());
dagger.attack(); // 输出: 进行刺击...

通过这种方式,我们可以轻松地添加新的刀具类型和攻击方式,而不需要修改现有的代码,这正是工厂方法模式和策略模式结合使用的强大之处。

观察者模式+状态模式

当然可以!我们可以通过引入状态模式来管理角色的状态变化。状态模式允许对象在其内部状态改变时改变其行为。在这种情况下,我们可以定义几种状态,比如“活着”、“濒死”和“死亡”,并通过这些状态来控制角色的行为。

以下是结合观察者模式和状态模式的完整实现:

定义状态接口和具体状态类

首先,我们需要定义一个状态接口和几个具体的状态类:

// 状态接口
interface State {void takeDamage(Character character, float damage);void attack(Character character, Character target);void heal(Character character, float amount);
}// 活着状态
class AliveState implements State {@Overridepublic void takeDamage(Character character, float damage) {character.setHealth(character.getHealth() - damage);System.out.println(character.getName() + " takes damage: " + damage + ". Remaining health: " + character.getHealth());if (character.getHealth() <= 0) {character.setState(new DeadState());} else if (character.getHealth() <= 10) {character.setState(new DyingState());}}@Overridepublic void attack(Character character, Character target) {System.out.println(character.getName() + " attacks " + target.getName());target.takeDamage(10.0f); // 假设每次攻击造成固定伤害}@Overridepublic void heal(Character character, float amount) {character.setHealth(Math.min(character.getHealth() + amount, 100.0f));System.out.println(character.getName() + " heals for " + amount + ". New health: " + character.getHealth());}
}// 濒死状态
class DyingState implements State {@Overridepublic void takeDamage(Character character, float damage) {character.setHealth(character.getHealth() - damage);System.out.println(character.getName() + " is dying and takes damage: " + damage + ". Remaining health: " + character.getHealth());if (character.getHealth() <= 0) {character.setState(new DeadState());}}@Overridepublic void attack(Character character, Character target) {System.out.println(character.getName() + " is too weak to attack.");}@Overridepublic void heal(Character character, float amount) {character.setHealth(Math.min(character.getHealth() + amount, 100.0f));if (character.getHealth() > 10) {character.setState(new AliveState());}System.out.println(character.getName() + " heals for " + amount + ". New health: " + character.getHealth());}
}// 死亡状态
class DeadState implements State {@Overridepublic void takeDamage(Character character, float damage) {System.out.println(character.getName() + " is already dead.");}@Overridepublic void attack(Character character, Character target) {System.out.println(character.getName() + " cannot attack because they are dead.");}@Overridepublic void heal(Character character, float amount) {System.out.println(character.getName() + " cannot be healed because they are dead.");}
}

修改 Character 类以支持状态模式

接下来,我们需要修改 Character 类,使其能够管理不同的状态:

import java.util.ArrayList;
import java.util.List;// 被观察者接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 观察者接口
interface Observer {void update(float damage); // 更新方法,用于接收伤害信息
}public class Character implements Subject, Observer {private String name;private float health = 100.0f; // 初始生命值private List<Observer> observers;private State state;public Character(String name) {this.name = name;this.observers = new ArrayList<>();this.state = new AliveState(); // 初始状态为活着}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(getDamage());}}public void attack(Character target) {state.attack(this, target);}public void takeDamage(float damage) {state.takeDamage(this, damage);notifyObservers(); // 通知所有观察者}public void heal(float amount) {state.heal(this, amount);}public void setState(State state) {this.state = state;}public String getName() {return name;}public float getHealth() {return health;}public void setHealth(float health) {this.health = health;}@Overridepublic void update(float damage) {System.out.println(name + " observes that someone took damage: " + damage);}
}

测试代码

最后,我们可以在主函数中测试这些功能:

public class Main {public static void main(String[] args) {Character hero = new Character("Hero");Character monster = new Character("Monster");// 让monster观察herohero.registerObserver(monster);// Hero 攻击 Monsterhero.attack(monster);// Monster 反击 Heromonster.attack(hero);// Hero 再次攻击 Monsterhero.attack(monster);// 尝试治愈死亡的Monstermonster.heal(50.0f);}
}

在这个例子中,角色的状态会在受到伤害或治疗时发生变化。当角色的生命值降到10以下时,进入“濒死”状态;当生命值降到0时,进入“死亡”状态。状态的变化会影响角色的行为,例如濒死状态下的角色不能攻击,死亡状态下的角色不能被治愈。

测试结果

好的,下面是运行上述代码后的测试结果:

Hero attacks Monster
Monster takes damage: 10.0. Remaining health: 90.0
Monster observes that someone took damage: 10.0
Monster attacks Hero
Hero takes damage: 10.0. Remaining health: 90.0
Hero attacks Monster
Monster takes damage: 10.0. Remaining health: 80.0
Monster observes that someone took damage: 10.0
Monster cannot be healed because they are dead.

解释:

  1. Hero 攻击 Monster

    • Hero 对 Monster 发起攻击,Monster 受到 10 点伤害,剩余生命值为 90。
    • Monster 观察到有人受到了伤害。
  2. Monster 反击 Hero

    • Monster 对 Hero 发起攻击,Hero 受到 10 点伤害,剩余生命值为 90。
    • Hero 观察到有人受到了伤害。
  3. Hero 再次攻击 Monster

    • Hero 再次对 Monster 发起攻击,Monster 受到 10 点伤害,剩余生命值为 80。
    • Monster 观察到有人受到了伤害。
  4. 尝试治愈死亡的 Monster

    • 尝试治愈已经死亡的 Monster,但由于 Monster 已经死亡,无法被治愈。

这个结果展示了角色在不同状态下的行为变化,以及观察者模式的通知机制。

命令模式

好的,我们可以结合命令模式来封装攻击命令,并将其传递给角色对象进行调用。命令模式的核心思想是将请求封装成对象,从而使你可以用不同的请求、队列或者日志请求来参数化其他对象。下面是如何在现有代码基础上添加命令模式的示例。

示例1

定义命令接口和具体命令类

首先,我们定义一个命令接口和具体的命令类:

// 命令接口
interface Command {void execute();
}// 具体命令类:攻击命令
class AttackCommand implements Command {private Character attacker;private Character target;public AttackCommand(Character attacker, Character target) {this.attacker = attacker;this.target = target;}@Overridepublic void execute() {attacker.attack(target);}
}

修改 Character 类以支持命令模式

接下来,我们需要在 Character 类中添加一个方法来接收和执行命令:

import java.util.ArrayList;
import java.util.List;// 被观察者接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 观察者接口
interface Observer {void update(float damage); // 更新方法,用于接收伤害信息
}public class Character implements Subject, Observer {private String name;private float health = 100.0f; // 初始生命值private List<Observer> observers;private State state;public Character(String name) {this.name = name;this.observers = new ArrayList<>();this.state = new AliveState(); // 初始状态为活着}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(getDamage());}}public void attack(Character target) {state.attack(this, target);}public void takeDamage(float damage) {state.takeDamage(this, damage);notifyObservers(); // 通知所有观察者}public void heal(float amount) {state.heal(this, amount);}public void setState(State state) {this.state = state;}public String getName() {return name;}public float getHealth() {return health;}public void setHealth(float health) {this.health = health;}@Overridepublic void update(float damage) {System.out.println(name + " observes that someone took damage: " + damage);}// 接收并执行命令的方法public void executeCommand(Command command) {command.execute();}// 获取当前角色受到的伤害private float getDamage() {return 10.0f; // 返回固定的伤害值}
}

测试代码

最后,我们在主函数中创建命令对象并执行命令:

public class Main {public static void main(String[] args) {Character hero = new Character("Hero");Character monster = new Character("Monster");// 让monster观察herohero.registerObserver(monster);// 创建攻击命令Command attackHero = new AttackCommand(monster, hero);Command attackMonster = new AttackCommand(hero, monster);// 执行命令hero.executeCommand(attackMonster); // Hero 攻击 Monstermonster.executeCommand(attackHero); // Monster 反击 Herohero.executeCommand(attackMonster); // Hero 再次攻击 Monster// 尝试治愈死亡的Monstermonster.heal(50.0f);}
}

运行结果

运行上述代码后,输出结果如下:

Hero attacks Monster
Monster takes damage: 10.0. Remaining health: 90.0
Monster observes that someone took damage: 10.0
Monster attacks Hero
Hero takes damage: 10.0. Remaining health: 90.0
Hero attacks Monster
Monster takes damage: 10.0. Remaining health: 80.0
Monster observes that someone took damage: 10.0
Monster cannot be healed because they are dead.

解释:

  1. Hero 攻击 Monster

    • Hero 对 Monster 发起攻击,Monster 受到 10 点伤害,剩余生命值为 90。
    • Monster 观察到有人受到了伤害。
  2. Monster 反击 Hero

    • Monster 对 Hero 发起攻击,Hero 受到 10 点伤害,剩余生命值为 90。
    • Hero 观察到有人受到了伤害。
  3. Hero 再次攻击 Monster

    • Hero 再次对 Monster 发起攻击,Monster 受到 10 点伤害,剩余生命值为 80。
    • Monster 观察到有人受到了伤害。
  4. 尝试治愈死亡的 Monster

    • 尝试治愈已经死亡的 Monster,但由于 Monster 已经死亡,无法被治愈。

通过这种方式,我们成功地将攻击命令封装成了对象,并通过命令模式来管理角色之间的交互。

示例2

理解命令模式的关键在于它提供了一种将请求封装成对象的方式,这使得你可以用不同的请求、队列或者日志请求来参数化其他对象。命令模式的主要优点包括:

  1. 解耦发送者和接收者:发送者(调用者)和接收者(执行者)之间没有直接依赖关系。
  2. 支持撤销操作:可以很容易地扩展命令类来支持撤销操作。
  3. 支持命令队列:可以将多个命令放入队列中,按顺序执行。

让我们通过一个更具体的例子来说明这一点。假设我们有一个游戏系统,其中角色可以执行多种动作,如攻击、移动和使用技能。我们可以使用命令模式来封装这些动作。

示例代码

定义命令接口和具体命令类
// 命令接口
interface Command {void execute();
}// 具体命令类:攻击命令
class AttackCommand implements Command {private Character attacker;private Character target;public AttackCommand(Character attacker, Character target) {this.attacker = attacker;this.target = target;}@Overridepublic void execute() {attacker.attack(target);}
}// 具体命令类:移动命令
class MoveCommand implements Command {private Character character;private String direction;public MoveCommand(Character character, String direction) {this.character = character;this.direction = direction;}@Overridepublic void execute() {character.move(direction);}
}// 具体命令类:使用技能命令
class UseSkillCommand implements Command {private Character character;private String skillName;public UseSkillCommand(Character character, String skillName) {this.character = character;this.skillName = skillName;}@Overridepublic void execute() {character.useSkill(skillName);}
}
修改 Character 类以支持命令模式
import java.util.ArrayList;
import java.util.List;// 被观察者接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 观察者接口
interface Observer {void update(float damage); // 更新方法,用于接收伤害信息
}public class Character implements Subject, Observer {private String name;private float health = 100.0f; // 初始生命值private List<Observer> observers;private State state;public Character(String name) {this.name = name;this.observers = new ArrayList<>();this.state = new AliveState(); // 初始状态为活着}@Overridepublic void registerObserver(Observer o) {observers.add(o);}@Overridepublic void removeObserver(Observer o) {observers.remove(o);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(getDamage());}}public void attack(Character target) {state.attack(this, target);}public void takeDamage(float damage) {state.takeDamage(this, damage);notifyObservers(); // 通知所有观察者}public void heal(float amount) {state.heal(this, amount);}public void move(String direction) {System.out.println(name + " moves " + direction);}public void useSkill(String skillName) {System.out.println(name + " uses skill: " + skillName);}public void setState(State state) {this.state = state;}public String getName() {return name;}public float getHealth() {return health;}public void setHealth(float health) {this.health = health;}@Overridepublic void update(float damage) {System.out.println(name + " observes that someone took damage: " + damage);}// 接收并执行命令的方法public void executeCommand(Command command) {command.execute();}// 获取当前角色受到的伤害private float getDamage() {return 10.0f; // 返回固定的伤害值}
}
测试代码
public class Main {public static void main(String[] args) {Character hero = new Character("Hero");Character monster = new Character("Monster");// 让monster观察herohero.registerObserver(monster);// 创建攻击命令Command attackHero = new AttackCommand(monster, hero);Command attackMonster = new AttackCommand(hero, monster);// 创建移动命令Command moveHero = new MoveCommand(hero, "north");Command moveMonster = new MoveCommand(monster, "south");// 创建使用技能命令Command useSkillHero = new UseSkillCommand(hero, "Fireball");Command useSkillMonster = new UseSkillCommand(monster, "Poison Breath");// 执行命令hero.executeCommand(attackMonster); // Hero 攻击 Monstermonster.executeCommand(attackHero); // Monster 反击 Herohero.executeCommand(moveHero);      // Hero 向北移动monster.executeCommand(moveMonster); // Monster 向南移动hero.executeCommand(useSkillHero);  // Hero 使用技能 Fireballmonster.executeCommand(useSkillMonster); // Monster 使用技能 Poison Breath// 尝试治愈死亡的Monstermonster.heal(50.0f);}
}

运行结果

运行上述代码后,输出结果如下:

Hero attacks Monster
Monster takes damage: 10.0. Remaining health: 90.0
Monster observes that someone took damage: 10.0
Monster attacks Hero
Hero takes damage: 10.0. Remaining health: 90.0
Hero moves north
Monster moves south
Hero uses skill: Fireball
Monster uses skill: Poison Breath
Monster cannot be healed because they are dead.

解释

  1. Hero 攻击 Monster

    • Hero 对 Monster 发起攻击,Monster 受到 10 点伤害,剩余生命值为 90。
    • Monster 观察到有人受到了伤害。
  2. Monster 反击 Hero

    • Monster 对 Hero 发起攻击,Hero 受到 10 点伤害,剩余生命值为 90。
    • Hero 观察到有人受到了伤害。
  3. Hero 向北移动

    • Hero 向北移动。
  4. Monster 向南移动

    • Monster 向南移动。
  5. Hero 使用技能 Fireball

    • Hero 使用技能 Fireball。
  6. Monster 使用技能 Poison Breath

    • Monster 使用技能 Poison Breath。
  7. 尝试治愈死亡的 Monster

    • 尝试治愈已经死亡的 Monster,但由于 Monster 已经死亡,无法被治愈。

通过命令模式,我们可以将不同的动作封装成命令对象,这样可以更容易地管理和扩展角色的行为。例如,可以轻松地添加新的命令类型,或者将多个命令放入队列中按顺序执行。

游戏中的mod

游戏MOD(Modification,即修改或扩展)是一种允许第三方开发者对游戏进行自定义和扩展的功能。实现游戏MOD的关键在于提供一种机制,使外部开发者能够安全地访问和修改游戏的某些部分,而不破坏游戏的核心逻辑或安全性。以下是实现游戏MOD的一些常见原理和技术:

1. 插件系统(Plugin System)

插件系统是最常见的实现MOD的方式之一。游戏引擎或框架提供一个标准化的API,允许外部开发者编写符合这些API的插件。这些插件可以动态加载到游戏中,从而实现功能的扩展。

实现步骤:
  1. 定义API:游戏开发者定义一组标准化的API,这些API允许MOD开发者访问和修改游戏的特定部分。
  2. 插件加载器:游戏引擎包含一个插件加载器,负责动态加载和卸载MOD。
  3. 沙盒环境:为了确保安全性和稳定性,通常会提供一个沙盒环境,限制MOD对游戏核心系统的访问。

2. 数据文件扩展

许多游戏允许MOD通过修改数据文件(如配置文件、纹理文件、模型文件等)来实现扩展。这种方法相对简单,但功能有限。

实现步骤:
  1. 数据文件格式:定义清晰的数据文件格式,允许MOD开发者创建或修改这些文件。
  2. 文件加载:游戏引擎在启动时或运行时加载这些数据文件,并根据文件内容进行相应的修改。

3. 脚本语言支持

许多游戏支持脚本语言(如Lua、Python等),允许MOD开发者编写脚本来扩展游戏功能。这种方法提供了较高的灵活性和可扩展性。

实现步骤:
  1. 嵌入脚本引擎:在游戏中嵌入一个脚本引擎,如Lua或Python。
  2. 暴露API:通过脚本引擎暴露一组API,允许脚本访问和修改游戏的特定部分。
  3. 脚本加载:游戏引擎在启动时或运行时加载并执行这些脚本文件。

4. 模块化设计

游戏的设计采用模块化的方式,每个模块负责一个特定的功能。MOD开发者可以替换或扩展这些模块,从而实现功能的扩展。

实现步骤:
  1. 模块化架构:游戏采用模块化架构,每个模块负责一个特定的功能。
  2. 模块加载:游戏引擎提供一个模块加载器,负责动态加载和卸载模块。
  3. 模块接口:定义清晰的模块接口,允许MOD开发者创建符合这些接口的新模块。

5. 开放源代码

对于一些开源游戏,开发者可以直接修改游戏的源代码,编译并运行修改后的版本。这种方法提供了最大的灵活性,但也需要更高的技术门槛。

实现步骤:
  1. 开放源代码:游戏开发者将游戏的源代码开放给社区。
  2. 编译工具:提供必要的编译工具和文档,帮助MOD开发者编译和运行修改后的游戏。

6. 文档和支持

无论采用哪种方式,提供详细的文档和支持都是非常重要的。这可以帮助MOD开发者更快地上手,并提高MOD的质量和稳定性。

实现步骤:
  1. 开发文档:编写详细的开发文档,介绍如何编写MOD、使用的API和最佳实践。
  2. 社区支持:建立社区论坛或聊天群组,提供技术支持和交流平台。
  3. 示例MOD:提供一些示例MOD,帮助开发者理解和学习。

示例:Minecraft MOD开发

Minecraft 是一个非常成功的支持MOD的游戏。它的MOD开发主要基于以下几点:

  1. 使用Java语言:Minecraft 是用Java编写的,MOD开发者也需要使用Java。
  2. Forge和Fabric API:这两个API提供了丰富的工具和方法,允许MOD开发者访问和修改游戏的各个方面。
  3. 模组加载器:Minecraft 使用Forge或Fabric作为模组加载器,负责加载和管理MOD。
  4. 社区支持:Minecraft 拥有一个庞大的开发者社区,提供了大量的文档、教程和支持。

总结

实现游戏MOD的关键在于提供一套标准化的API和工具,使外部开发者能够安全、方便地扩展游戏功能。通过插件系统、数据文件扩展、脚本语言支持、模块化设计、开放源代码等方式,可以有效地实现这一目标。同时,提供详细的文档和支持也是非常重要的,这有助于提高MOD的质量和稳定性。

dll文件

DLL(Dynamic Link Library,动态链接库)是一种在Windows操作系统中使用的文件格式。DLL 文件包含可以由多个程序同时使用的代码和数据。通过使用DLL,可以实现代码重用、节省内存和磁盘空间,并且可以更方便地更新和维护软件。

DLL 的主要特点

  1. 代码重用

    • 多个应用程序可以共享同一个DLL文件中的代码,避免了重复编写相同的代码。
  2. 节省内存和磁盘空间

    • 由于多个应用程序可以共享同一个DLL文件,因此不需要为每个应用程序复制相同的代码,从而节省了内存和磁盘空间。
  3. 易于更新和维护

    • 当需要更新或修复DLL中的代码时,只需更新DLL文件本身,而无需重新编译和重新发布所有使用该DLL的应用程序。
  4. 模块化设计

    • DLL文件可以将应用程序的功能划分为多个模块,每个模块负责一个特定的任务,这有助于提高代码的组织性和可维护性。

DLL 的工作原理

  1. 编译和链接

    • 在编译阶段,编译器生成一个DLL文件(扩展名为.dll)和一个导入库文件(扩展名为.lib)。导入库文件包含了DLL中导出函数的信息,供链接器使用。
    • 在链接阶段,链接器使用导入库文件将应用程序与DLL中的函数关联起来。
  2. 加载和卸载

    • 当应用程序启动时,Windows操作系统会自动加载所需的DLL文件。如果多个应用程序需要同一个DLL,操作系统会确保只加载一次,并允许多个应用程序共享该DLL。
    • 当应用程序结束时,操作系统会卸载不再需要的DLL文件。

创建和使用DLL

创建DLL
  1. 定义导出函数

    • 在DLL中,需要定义哪些函数可以被外部程序调用。通常使用__declspec(dllexport)关键字来导出函数。
    // MyDll.cpp
    #include <windows.h>extern "C" __declspec(dllexport) void MyFunction() {MessageBox(NULL, L"Hello from DLL!", L"My DLL", MB_OK);
    }
    
  2. 编译DLL

    • 使用编译器(如Visual Studio)编译上述代码,生成DLL文件和导入库文件。
    cl /LD MyDll.cpp
    

    这将生成MyDll.dllMyDll.lib文件。

使用DLL
  1. 链接导入库

    • 在应用程序中,需要链接DLL的导入库文件。
    // MyApplication.cpp
    #include <windows.h>extern "C" {__declspec(dllimport) void MyFunction();
    }int main() {MyFunction();return 0;
    }
    
  2. 编译和运行应用程序

    • 使用编译器编译应用程序,并链接导入库文件。
    cl MyApplication.cpp MyDll.lib
    

    运行生成的可执行文件MyApplication.exe,将会调用DLL中的MyFunction函数。

动态加载DLL

除了静态链接导入库外,还可以在运行时动态加载DLL。这通常使用LoadLibraryGetProcAddressFreeLibrary函数来实现。

#include <windows.h>
#include <iostream>typedef void (*MyFunctionType)();int main() {HINSTANCE hDLL = LoadLibrary(L"MyDll.dll");if (hDLL != NULL) {MyFunctionType MyFunction = (MyFunctionType)GetProcAddress(hDLL, "MyFunction");if (MyFunction != NULL) {MyFunction();} else {std::cerr << "Failed to get function address." << std::endl;}FreeLibrary(hDLL);} else {std::cerr << "Failed to load DLL." << std::endl;}return 0;
}

总结

DLL 是Windows操作系统中的一种重要文件格式,用于实现代码重用、节省资源和模块化设计。通过定义导出函数、编译生成DLL文件和导入库文件,可以在多个应用程序中共享和使用这些函数。动态加载DLL则提供了更大的灵活性,允许在运行时根据需要加载和卸载DLL。
ps:
如果游戏MOD使用了DLL文件,那么最可能采用的是插件系统或脚本语言支持的方法。这两种方法都可以很好地利用DLL文件来实现扩展功能。下面详细解释这两种方法及其与DLL的关系:

  1. 插件系统(Plugin System)
    实现原理:
    定义API:游戏开发者定义一组标准化的API,这些API允许MOD开发者访问和修改游戏的特定部分。
    插件加载器:游戏引擎包含一个插件加载器,负责动态加载和卸载MOD。
    沙盒环境:为了确保安全性和稳定性,通常会提供一个沙盒环境,限制MOD对游戏核心系统的访问。
    使用DLL的方式:
    导出函数:MOD开发者编写一个DLL文件,并在其中定义导出函数。这些函数可以通过__declspec(dllexport)关键字导出。
    动态加载:游戏引擎在启动时或运行时使用LoadLibrary和GetProcAddress函数动态加载DLL,并调用其中的导出函数。

相关文章:

游戏中的设计模式及杂项

概述 如果要做以下游戏功能会用到哪些设计模式。比如创建一个人物角色&#xff0c;这个角色可以装备刀&#xff0c;然后角色可以用刀砍怪物&#xff0c;造成流血。 对于这个游戏功能&#xff0c;可以使用以下设计模式&#xff1a; 工厂模式&#xff08;Factory Pattern&#x…...

Docker网络和overlay的基础讲解

本人发现了两篇写的不错的文章&#xff1a;Docker网络 - docker network详解-CSDN博客&#xff0c;Docker 容器跨主机通信 overlay_docker overlay 网络-CSDN博客 因为这两篇文章中含有大量的例子&#xff0c;新手看起来毫不费力。于是我偷了个小懒&#xff0c;在本篇文章中没有…...

分布式数据库:深入探讨架构、挑战与未来趋势

引言 在数字化时代&#xff0c;数据已成为企业的核心资产。随着数据量的爆炸性增长和业务需求的多样化&#xff0c;传统的集中式数据库已难以满足现代应用对于高可用性、可扩展性和性能的需求。分布式数据库以其独特的优势&#xff0c;如数据的高可用性、容错性和可扩展性&…...

基于Springboot+Vue的仓库管理系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…...

基于立体连接与开源链动 2+1 模式的新商业路径探索

摘要&#xff1a;本文深入剖析了立体连接的内涵&#xff0c;包括其核心关键词、连接路径与主体&#xff0c;同时详细阐述了开源链动 2 1 模式、AI 智能名片和 S2B2C 商城小程序源码的特点与功能。在此基础上&#xff0c;深入研究这些要素的融合方式及其在商业实践中的应用&…...

开启鸿蒙开发之旅:核心组件及其各项属性介绍——布局容器组件

写在前面 组件的结构 rkTS通过装饰器 Component 和 Entry 装饰 struct 关键字声明的数据结构&#xff0c;构成一个自定义组件。 自定义组件中提供了一个 build 函数&#xff0c;开发者需在该函数内以链式调用的方式进行基本的 UI 描述 今天我们要学习的就是写在build 函数里的系…...

RabbitMQ 全面解析:语法与其他消息中间件的对比分析

1. 引言 在分布式系统和微服务架构中&#xff0c;消息中间件扮演着重要的角色。它们能够解耦服务、平衡负载、提高系统的可扩展性和可靠性。RabbitMQ 是其中广受欢迎的一种。本文将从 RabbitMQ 的基础概念、语法介绍、以及与其他消息中间件的对比角度&#xff0c;全面剖析其在…...

Three.js 搭建3D隧道监测

Three.js 搭建3D隧道监测 Three.js 基础元素场景scene相机carema网络模型Mesh光源light渲染器renderer控制器controls 实现3d隧道监测基础实现道路实现隧道实现多个摄像头点击模型进行属性操作实现点击模型发光效果 性能监视器stats引入使用 总结完整代码 我们将通过three.js技…...

「IDE」集成开发环境专栏目录大纲

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「IDE」集成开发环境&#x1f4da;全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…...

MySQL-初识数据库

目录 一、数据库基础概念 1、SQL 2、数据&#xff08;Data&#xff09; 3、数据库&#xff08;DB&#xff09; 4、数据库管理系统DBMS 5、数据库系统DBS 6、关系模型&#xff08;Relational Model&#xff09; 7、E-R图 8、常见的数据库 9、数据库基本操作 一、数据库…...

初始 html

html 文件结构 html 标签是整个 html 文件的根标签(最顶层标签) head 标签中写页面的属性. body 标签中写的是页面上显示的内容 title 标签中写的是页面的标题 <html><head><title>这是一个标题</title></head><body></body> <…...

前端 call、bind、apply的实际使用

目录 一、call 1、继承的子类可以使用父类的方法 2、可以接收任意参数 二、call、apply、bind比较 1、案例一 2、案例二 三、总结 这个三个方法都是改变函数的this指向的方法。 一、call 代码&#xff1a; const obj{uname:"pink"}function fn(){console.log…...

非关系型数据库NoSQL的类型与优缺点对比

NoSQL数据库根据数据模型和应用场景主要分为四种类型&#xff1a;键值型、列族型、文档型和图形型。以下是对每种类型的详细描述&#xff0c;包括其应用场景、优缺点的比较&#xff1a; 1. 键值型数据库 (Key-Value Store) 典型代表 RedisMemcachedAmazon DynamoDB 应用场景…...

面试击穿mysql

Mysql三大范式: 第一范式&#xff08;1NF&#xff09;&#xff1a; 不符合第一范式的典型情况是在一个字段中存放多种不同类型的详细信息。例如&#xff0c;在商品表中&#xff0c;若将商品名称、价格和类型都存储在同一个字段中&#xff0c;会带来诸多弊端。首先&#xff0c;在…...

PyQt5超详细教程终篇

PyQt5超详细教程 前言 接&#xff1a; [【Python篇】PyQt5 超详细教程——由入门到精通&#xff08;序篇&#xff09;](【Python篇】PyQt5 超详细教程——由入门到精通&#xff08;序篇&#xff09;-CSDN博客) 建议把代码复制到pycahrm等IDE上面看实际效果&#xff0c;方便理…...

Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别

目录 一、概念 1、纹理过滤 2、邻近过滤 3、线性过滤 二、邻近过滤和线性过滤的区别 三、源码下载 一、概念 1、纹理过滤 当纹理被应用到三维物体上时&#xff0c;随着物体表面的形状和相机视角的变化&#xff0c;会导致纹理在渲染过程中出现一些问题&#xff0c;如锯齿…...

Elasticsearch实战应用:从入门到精通

在当今这个数据爆炸的时代&#xff0c;如何快速、有效地从海量数据中检索信息&#xff0c;已经成为了许多企业和开发者面临的挑战。Elasticsearch&#xff0c;作为一个基于Lucene的搜索引擎&#xff0c;以其强大的全文搜索能力、分布式特性以及易用性&#xff0c;成为了解决这一…...

axios平替!用浏览器自带的fetch处理AJAX(兼容表单/JSON/文件上传)

fetch 是啥&#xff1f; fetch 函数是 JavaScript 中用于发送网络请求的内置 API&#xff0c;可以替代传统的 XMLHttpRequest。它可以发送 HTTP 请求&#xff08;如 GET、POST 等&#xff09;&#xff0c;并返回一个 Promise&#xff0c;从而简化异步操作 基本用法 /* 下面是…...

【优选算法 — 滑动窗口】水果成篮 找到字符串中所有字母异位词

水果成篮 水果成篮 题目描述 因为只有两个篮子&#xff0c;每个篮子装的水果种类相同&#xff0c;如果从 0 开始摘&#xff0c;则只能摘 0 和 1 两个种类 &#xff1b; 因为当我们在两个果篮都装有水果的情况下&#xff0c;如果再走到下一颗果树&#xff0c;果树的水果种类…...

Go 数据库查询与结构体映射

下面是关于如何使用 Go 进行数据库查询并映射数据到结构体的教程&#xff0c;重点讲解 结构体字段导出 和 db 标签 的使用。 Go 数据库查询与结构体映射教程 在 Go 中&#xff0c;我们可以使用 database/sql 或 sqlx 等库与数据库进行交互。为了方便地将数据库查询结果映射到结…...

Wi-Fi背后的工作原理与技术发展历程介绍【无线通信小百科】

1个视频说清楚WIFI&#xff1a;频段/历程/技术参数/常用模块 智能手机拥有率越来越高的今天&#xff0c;大家已经习惯了通过无线网络上网的方式。除了在外面需要用手机流量&#xff0c;我们通常在家里或者机场&#xff0c;商场都可以通过Wi-Fi连接上网。本期文章将为大家介绍Wi…...

2024 年(第 7 届)“泰迪杯”数据分析技能赛B 题 特殊医学用途配方食品数据分析 完整代码 结果 可视化分享

一、背景特殊医学用途配方食品简称特医食品&#xff0c;是指为满足进食受限、消化吸收障碍、代谢素乱或者特定疾病状态人群对营养素或者膳食的特殊需要&#xff0c;专门加工配置而成的配方食品&#xff0c;包括0月龄至12月龄的特殊医学用途婴儿配方食品和适用于1岁以上的特殊医…...

STM32学习笔记------编程驱动蜂鸣器实现音乐播放

1. 硬件准备 STM32开发板&#xff1a;STM32F407系列蜂鸣器&#xff1a;常见的蜂鸣器分为两类&#xff1a;有源蜂鸣器和无源蜂鸣器。若使用有源蜂鸣器&#xff0c;只需提供电源和控制信号即可&#xff1b;若使用无源蜂鸣器&#xff0c;则需要控制频率。外接电源&#xff08;可选…...

ubuntu18.04 安装与卸载NCCL conda环境安装PaddlePaddle

cuda版本11.2 说明PaddlePaddle需要安装NCCL 1、Log in | NVIDIA Developer 登录官网 找到对应版本 官方提供了多种安装方式&#xff0c;本文使用Local installers (x86)本地安装 点击对应的版本下载如&#xff1a; nccl-local-repo-ubuntu1804-2.8.4-cuda11.2_1.0-1_amd6…...

AI有鼻子了,还能远程传输气味,图像生成香水

众所周知&#xff0c;图像、音乐能用AI生成&#xff0c;但出乎意料的是&#xff0c;气味也行。最近&#xff0c;一个名叫Osmo的初创公司宣布&#xff0c;他们成功地将气味数字化了。第一个成功的案例是“新鲜的夏季李子”&#xff0c;而且复现出的味道“闻起来”很不错。整个过…...

学习配置dify过程记录

最近在学习安装 Dify 并集成 Ollama 和 Xinference&#xff0c;学习过程中遇到很多问题&#xff0c;所以我都记录下来。 本人电脑环境&#xff1a;MacBook Pro 15.1系统 基本是基于B站教程一步步搭建: 【Dify快速入门 | 本地部署Dify基于Llama 3.1和OpenAI创建聊天机器人与知…...

简易抽奖器源码以及打包操作

import wx import random import time# 定义Myframe类,继承Frame class Myframe(wx.Frame):# 奖品rewards [桥本香奈, 二代CC, NaNa, 情深叉]# 构造方法def __init__(self):# 父类初始化super().__init__(None, title主界面, size(500, 400), pos(500, 200))# 创建面板&#x…...

一文了解什么是腾讯云开发

一文了解什么是腾讯云开发 关于云开发的猜想腾讯云开发腾讯云开发的优势无服务跨平台轻松托管节约成本 快速上手云开发环境快速搭建管理后台 云开发体验 关于云开发的猜想 说到云开发&#xff0c;作为开发者的大家是否大概就有了想法。比如说过去的开发工作都是在自己本地电脑…...

[CKS] K8S NetworkPolicy Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于不安全项目修复的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Ne…...

【JAVA】Java基础—面向对象编程:构造方法-实现一个Car类,包含多个构造方法,创建不同的汽车对象

在Java中&#xff0c;构造方法则是用于创建对象的特殊方法。通过构造方法&#xff0c;可以在创建对象时初始化其属性。构造方法的重载允许我们根据不同的需求定义多个构造方法&#xff0c;从而灵活地创建对象。 我们可以将汽车的构造方法比作汽车的配置选项。比如&#xff0c;…...

北京做网站的公司哪家好/周口网站seo

2019独角兽企业重金招聘Python工程师标准>>> 今天在交流群里看到有一位仁兄问了一个java String对象方面的问题&#xff01; 题目如下&#xff1a; String s "abcd";s "efgh";s s.substring(2,5); s s.toUpperCase()return s.toString();…...

绍兴疫情最新消息今天封城/seo最强

我真的贪恋这时光。。。 没将这美好用上。 都说该找到个感兴趣&#xff0c;天天快乐的工作。可是多么的难找&#xff0c;真的找到了80%符合想象的&#xff0c;是不是要从1-2千块干起呢&#xff1f; 路漫漫&#xff0c;总感觉冥冥中有条路是给聪明人或是执着人留着的捷径&#x…...

做银行设计有好的网站参考吗/建站推广

学什么&#xff0c;比穿什么衣服的问题更难&#xff0c;因为职业的背后&#xff0c;更多的是抉择而不是选择&#xff0c;选错一件衣服可以重来&#xff0c;而选错一个职业所面对的结果&#xff0c;是非常让人痛苦的。本文是小千对想转行IT行业的你最真挚的建议。对于任何一个人…...

十堰网站建设报价/百度推广账户优化

UML里边界类、控制类和实体类三类讲解 2011年系统分析师考点分析之一 一&#xff0e;UML将类分为哪三个类&#xff1a; 1.边界类(Boundry Class)&#xff1b; 2.实体类(Entity Class)&#xff1b; 3.控制类(Control Class)&#xff1b; 二&#xff0e;边界类 1.用来描述什…...

网站备案做网站要转移吗/软文发布推广平台

01 漏洞描述 HTTP的无状态性&#xff0c;导致Web应用程序必须使用会话机制来识别用户。一旦与Web站点建立连接(访问、登录)&#xff0c;用户通常会分配到一个Cookie&#xff0c;随后的请求&#xff0c;都会带上这个Cookie&#xff0c;这样Web站点就很容易分辨请求来自哪个用户&…...

网站开发论文简要/环球网疫情最新消息

DSPc语言教程.doc电气专业词汇集散控制系统——Distributed Control System(DCS)现场总线控制系统——Fieldbus Control System(FCS)监控及数据采集系统——Supervisory Control And Data Acqusition(SCADA)可编程序控制器——Programmable Logic Controller(PLC) 可编程计算机…...