目录

<游戏演示>

<项目内容>

(1) 项目内容

<项目分析> 

(1) 游戏策划

(2) 游戏美术

(3) 游戏程序

 <项目实现>

(1) 游戏角色(Player)

(2) 小怪(Enemy)

(3) UI界面

(4) 摄像机(Camera)

(5) 公告板(Billboard)

(6) 游戏场景(Scene)

<项目源码>​​​​​​​


<游戏演示>

    

    

    

    

阿里云盘分享https://www.aliyundrive.com/s/tty5y5BumD1  提取码:ov67

<项目内容>

(1) 项目内容

JUNGLE RULES是一款Made With Unity2D 的横版闯关游戏。主要能实现以下功能:

1.人物的控制:A键向左跑动,D键向右跑动,Q键进行攻击模式切换,J键进行攻击(持刀模式下为劈斩,持枪模式下为射击),K键进行跳跃(可进行二段跳),L键读取告示板。人物受击时扣血,血槽空时死亡,死亡后再当前关卡重生。持刀攻击到小怪时产生刀锋效果,持枪攻击到小怪时产生爆炸效果。

2.简单的小怪AI:两类怪物,一类持剑的小怪,一类非持剑的小怪。两类小怪均能实现在指定范围内随机游走的功能。当玩家进入小怪警戒范围后,小怪自动向玩家靠近。玩家碰到小怪即掉血,持剑小怪靠近人物时同步进行挥剑劈砍。小怪受击红色闪烁并扣血,小怪死亡时消失。

3.UI界面:主界面显示游戏题目,开始游戏(PLAY)按钮和退出游戏(QUIT)按钮,均能进行逻辑的交互。游戏界面左上方显示人物血条和子弹数量,会随具体数值变化。游戏结束界面显示结束语和退出游戏按钮。

4.关卡的搭建:游戏主要有两个关卡,新手村关卡和主要关卡。新手村关卡搭建简单地图。主要关卡设计成迷宫形式。玩家在可站立的地图块上进行操作,若掉出地图死亡重生。

5.其它对象及逻辑:告示板——人物靠近告示板按下L键能显示告示内容。传送阵——人物进入传送阵后自动进入下一个关卡。游戏相机——自动跟随人物,小怪受击时相机震动。

<项目分析> 

(1) 游戏策划

1.1游戏剧情:

        森林里出现了许多带头盔的绿色怪物,威胁到了人们的生存。为此,猎人带着刀枪向森林出发,打败小怪,还给人们平静的生活。

1.2游戏关卡:

        游戏分为两个关卡。为了引导新玩家慢慢熟悉游戏操作,在新手村关卡搭建简单的地图,置放持剑小怪和非持剑小怪各一只,让玩家了解小怪的攻击模式。新手村关卡设置给予玩家操作提示信息的告示板,玩家可以在需要时进行读取。当玩家适应完操作后,可以自主选择进入传送阵到达主关卡。

        主关卡搭建复杂的地图,在相机视角受限的情况下,玩家无法了解到整张地图的信息,只能慢慢探索。在主关卡各处设置多只小怪,增加游戏难度。另外,玩家还将面临掉出地图死亡的风险,在地图的设计上需要能体现出这样的元素。当玩家完成探索后即为为森林带来了和平,玩家通过位于关卡深处的传送阵进入结束场景,游戏结局。

1.3游戏平衡:

        人物的生命值设置为30,人物最大载弹量设置为7,角色攻击伤害设置为2,小怪的生命值均设置为10,非持剑小怪的伤害设置为1,持剑小怪的伤害设置为3。总体上游戏难度偏简单,不给予玩家过大的操作压力。虽然持剑小怪攻击频率较快,伤害也高,但只要玩家持枪攻击便可无伤击败。

(2) 游戏美术

        游戏整体美术风格为像素风。游戏主题为猎人,森林,因此在素材的选择上多采用绿色。菜单场景,新手村场景,主场景,结束场景均应用不同的背景图片。利用地图块搭建地图,并用农场主题的素材包进行装饰。

        游戏素材均来自于Unity官方资源商店和网络交易平台,有偿获得,不存在美术版权的侵犯问题。

(3) 游戏程序

3.1主要涉及的对象及功能。

3.1.1游戏角色(Player)

        游戏角色自身具备的属性值为:移动速度,跳跃速度,人物生命值,攻击伤害。

        游戏角色的五项动作为:待机,跑动,跳跃,掉落,攻击。首先在显示层,我们需要利用控制人物动画的Animator组件实现动画的切换。然后在逻辑层面,我们需要在C#脚本中编写相关函数,当系统收到键盘相应的输入并且满足条件时,调用函数执行相关逻辑,最终实现一个整体视觉效果上的动作的实现。

        游戏角色作为游戏中最重要的组成部分,和游戏中的各类物体都有交互。我们需要检测游戏和物体的碰撞,然后触发相应的函数。人物和小怪碰撞时,调用人物受伤的函数,子弹以及刀剑的碰撞框和小怪碰撞时,调用小怪的受伤函数。人物和传送门碰撞时,调用传送函数进入下一个场景。人物和公告板碰撞时,按L调用显示公告信息的函数。
3.1.2小怪(Enemy)

        游戏小怪自身具备的属性为:移动速度,小怪生命值,小怪伤害。

        游戏小怪的三项动作为:待机,跑动,攻击。同样在显示层利用Animator组件进行动画的切换。在逻辑层用C#脚本控制Animator组件进行切换。

        游戏有两种不同的小怪,但两只小怪在共有的基本逻辑的实现上是类似的,我们编写抽象基类Enemy,在Enemy的基础上继承出持剑小怪(EnemySK)和非持剑小怪(EnemyNSK)。在基类中实现小怪被击受伤,击打到人物人物受伤,小怪受伤红色闪烁三种基本逻辑。在派生类的脚本中对小怪动画切换逻辑和随机游走进行编写。

3.1.3 UI界面(Canvas)

        在主界面中显示游戏主题“JUNGLE RULES”,引导语“Defeat Enemies And Save People!”引导玩家进入基本的游戏剧情。主界面设置两个按钮,单击开始游戏(PLAY)按钮,进入新手村场景。单击退出游戏(QUIT)按钮,退出程序。游戏界面能够获取人物的生命值,子弹数两项参数,动态地变化血量槽和子弹数槽。结束界面中显示结束语“Appreciation To Your Bravery”为玩家的勇气点赞,设置退出按钮,单击退出游戏(QUIT)按钮,退出程序。

3.1.4 摄像机(Main Camera)

        摄像机始终跟随人物显示地图画面,确保人物始终在画面居中偏下的位置。与此同时,摄像机不能超出地图边界,显示空白画布的内容。当人物跳出地图时,摄像机被限制在边界范围内。摄像机也有Animator组件,小怪受击时实现相机震动动画。

3.1.5 告示板(Billboard)和传送阵(Trans)

        这两个对象实现逻辑类似,都是利用了碰撞体。告示板检测到和人物的碰撞且键盘输入L时显示告示信息。人物离开后告示信息自动消失。传送阵利用Unity引擎的场景管理类(SceneManagement)进行场景的跳转。

3.2场景的划分

   
        游戏主要分为主菜单场景,新手村场景,主关卡场景,结束场景四个场景,顺序进行。

 <项目实现>

(1) 游戏角色(Player)

    

//Player Controller(Script)
public class PlayerController : MonoBehaviour
{
public float runSpeed;//人物奔跑速度
public float jumpSpeed;//人物第一次弹跳速度
public float doubleJumpSpeed;//人物第二次弹跳速度

private Rigidbody2D myRigidbody;//刚体组件
private Animator myAnim;//动画组件
private BoxCollider2D myFeet;//方形碰撞体组件
private bool isGround; //记录脚是否接触地面
private bool canDoubleJump;//判断能否进行二段跳

// Start is called before the first frame update
void Start()
{
myRigidbody = GetComponent<Rigidbody2D>();//调用对象的刚体组件
myAnim = GetComponent<Animator>();//调用对象动画组件
myFeet = GetComponent<BoxCollider2D>();//调用对象方形碰撞体组件
}

    // Update is called once per frame
void Update()
{
    Run();//实现人物左右跑动和动画显示
    Flip();//左右跑动时素材水平翻转
    Jump();//实现人物跳跃逻辑
    CheckGrounded();//检测人物是否接触地面
    SwitchAnimation();//实现人物跳跃时的动画切换
    SwitchMode();//切换攻击模式
}
 
//Player Health(Script)
public class PlayerHealth : MonoBehaviour
{
public int Health;//人物生命值
private Animator myAnim;//动画组件
    // Start is called before the first frame update
    void Start()
    {
        Healthbar.HealthMax = Health;//设置UI界面的生命条
        Healthbar.HealthCurrent = Health;//设置UI界面的生命条
     myAnim=GameObject.FindGameObjectWithTag("Player").GetComponent<Animator>();
    }//调用Player的动画组件

    // Update is called once per frame
    void Update()
    {
        if (Health <= 0)
        {
            Invoke("Restart", 3f);//死亡在3秒后重生
        }
        if (transform.position.y < -20)//掉出地图判断为死亡
        {
            Health = 0;
            Healthbar.HealthCurrent = Health;
        }
    }
    public void DamagePlayer(int damage);//人物受伤函数,由小怪调用
void Restart();//重生函数
}

PlayerAttack用于实现人物持刀攻击,BulletHit用于实现人物持枪攻击

//Player Attack(Script)
public class PlayerAttack : MonoBehaviour
{
    public int damage;//攻击伤害
    public float time; //攻击动作持续时间
    public float startTime;//攻击动作开始时间
    public GameObject SwordPrefab;//攻击效果

    private Animator anim;//动画组件
    private PolygonCollider2D collider2D;//多边形碰撞体组件
    private bool CanAttack;//能否攻击(一次攻击完之后才能进行下一次攻击)

    // Start is called before the first frame update
    void Start()
    {   //调用Player动画组件
        anim = GameObject.FindGameObjectWithTag("Player").GetComponent<Animator>();
        collider2D = GetComponent<PolygonCollider2D>();//调用碰撞体组件
        CanAttack = true;
    }

    // Update is called once per frame
    void Update()
    {
        Attack();//攻击实现函数
}
Attack()//检测输入 调用协程
    IEnumerator StartAttack()//协程 等待一定时间激活攻击碰撞框
    IEnumerator disableHitBox()//协程 等待一定时间取消攻击碰撞框
    void OnTriggerEnter2D(Collider2D other)//检测到碰撞调用小怪受伤函数
}

//Bullet Hit(Script)
public class BulletHit : MonoBehaviour
{
    private int Bullet = 7;//设置最大子弹数
    private bool canShoot = true;//标记是否有子弹
    public GameObject BulletPrefab;//子弹预制体
private Animator anim;//动画组件
    // Start is called before the first frame update
    void Start()
    {
        Bulletbar.BulletMax = Bullet;//设置UI界面的子弹槽
        Bulletbar.BulletCurrent = Bullet;//设置UI界面的子弹槽
        anim = GameObject.FindGameObjectWithTag("Player").GetComponent<Animator>();
        //调用player的动画组件
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetButtonDown("Attack") && anim.GetBool("Armed"))//持枪状态下按J
        {
            if (Bullet > 0)//有子弹
            {
                anim.SetTrigger("Attack");//设置攻击动画
                Instantiate(BulletPrefab, transform.position, transform.rotation);
                //在枪口处产生子弹
                Bullet -= 1;//子弹数减1
            }
        }
        if (Input.GetButtonDown("Loading"))//实现装弹
        {
            Bullet = 7;
        }
        Bulletbar.BulletCurrent = Bullet;//实时给UI界面传子弹数
    }
}

//Bullet(Script)
public class Bullet : MonoBehaviour
{
    public float speed;//子弹飞行速度
    public int damage;//子弹伤害
    public float destroyDistance; //子弹最长飞行距离
    public float time;//产生爆炸效果并在time秒后消除
    public GameObject ImpactEffect;//子弹爆炸效果

    private Rigidbody2D rb2d;//刚体组件
    private Vector3 startPos;//三维向量记录子弹出射位置

    // Start is called before the first frame update
    void Start()
    {
        rb2d = GetComponent<Rigidbody2D>();//调用对象刚体组件
        rb2d.velocity = transform.right * speed;//设置飞行速度
        startPos = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        float distance = (transform.position - startPos).sqrMagnitude;//计算已飞行的距离
        if (distance > destroyDistance)//超出飞行距离自动消除
        {
            Destroy(gameObject);
        }
    }
void OnTriggerEnter2D(Collider2D other)//碰撞到小怪调用小怪受伤函数 
//产生子弹爆炸效果
}

(2) 小怪(Enemy)

       

   

//Enemy(Script)
public abstract class Enemy : MonoBehaviour
{
    public int Health;//小怪生命值
    public int damage;//小怪伤害
    public float flashTime;//红色闪烁时间
    public float DeathTime;//死亡动画播放时间
    private SpriteRenderer sr;//图像渲染组件
    private Color originalColor;//初始颜色
    private PlayerHealth playerHealth;//玩家生命值

    // Start is called before the first frame update
    public void Start()
    {
        playerHealth = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerHealth>();//获取生命
        sr = GetComponent<SpriteRenderer>();//调用组件
        originalColor = sr.color;//保存初始色彩
    }

    // Update is called once per frame
    public void Update()
    {
        
    }
    public void TakeDamage(int damage) //小怪受伤函数
    void FlashColor(float time) //小怪红色闪烁函数
    void ResetColor()//重新设置为原来的颜色
    void OnTriggerEnter2D(Collider2D other)//碰撞到人物人物扣血
}

//Knight(Script)
public class Knight : Enemy
{
    public float speed;//小怪移动速度
    public float startWaitTime;//小怪等待时间
    private float waitTime;//记录到达某点已经过的时间
    private Rigidbody2D myRigidbody;//刚体组件

    public Transform movePos;//移动位置
    public Transform leftPos;//巡逻范围最左端
    public Transform rightPos;//巡逻范围最右端
    private Transform playerTransform;//人物位置
    private Animator myAnim;
    private BoxCollider2D Bcollider2D;

    // Start is called before the first frame update
    public void Start()
    {
        base.Start();//调用基类的Start()函数
        waitTime = startWaitTime;//初始化等待时间
        movePos.position = GetRandomPos();//初始化小怪移动位置为随机位置
        myAnim = GetComponent<Animator>();
        Bcollider2D = GetComponent<BoxCollider2D>();
        playerTransform = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();//获得人物位置
    }

    // Update is called once per frame
    public void Update()
    {
        base.Update();//调用基类的Update()函数
        if (Health > 0)
        {
            Guard();//进行巡逻
        }
        else
        {
            myAnim.SetTrigger("Die");//调用死亡动画
            Bcollider2D.enabled = false;//小怪碰撞体失效
            Invoke("KillEnemy", DeathTime);//死亡动画放完 销毁物体
        }
    }
    void KillEnemy()//销毁物体
    Vector2 GetRandomPos()//获得随机位置
    void Flip()//小怪左右游走时小怪图像的水平翻转
    void Guard()//随机游走 追击角色实现函数 
}

(3) UI界面

   

//Health bar(Script)
public class Healthbar : MonoBehaviour
{
    public Text HealthText;//UI上显示的生命值
    public static int HealthCurrent;//当前生命
    public static int HealthMax;///最大生命

    private Image healthbar;//生命条图像
    // Start is called before the first frame update
    void Start()
    {
        healthbar = GetComponent<Image>();//调用生命条
        HealthCurrent = HealthMax;
    }

    // Update is called once per frame
    void Update()
    {
        healthbar.fillAmount = (float)HealthCurrent / (float)HealthMax;//设置生命条填充量
        HealthText.text = HealthCurrent.ToString() + "/" + HealthMax.ToString();//设置生                                    
                                                                                  命值
    }
}

//Bullet Bar(Script)
public class Bulletbar : MonoBehaviour
{
    public Text BulletText;//UI上显示的子弹数
    public static int BulletCurrent;//当前子弹数
    public static int BulletMax;//最大子弹数

    private Image bulletbar;//子弹条图像
    // Start is called before the first frame update
    void Start()
    {
        bulletbar = GetComponent<Image>();//调用子弹条
        //HealthCurrent = HealthMax;
    }

    // Update is called once per frame
    void Update()
    {
        bulletbar.fillAmount = (float)BulletCurrent / (float)BulletMax;//设置子弹条填充量
        BulletText.text = BulletCurrent.ToString() + "/" + BulletMax.ToString();//设置子 
                                                                                  弹值
    }
}

(4) 摄像机(Camera)

       

Camera Follow(Script):
public class CameraFollow : MonoBehaviour
{
    public Transform target;//跟踪目标 (设置为Main Camera)
    public float smoothing;//平滑常数

    public Vector2 minPosition;//跟踪边界左下方
    public Vector2 MaxPosition;//跟踪边界右上方

    // Start is called before the first frame update
    void Start()
    {
        GameController.camShake = GameObject.FindGameObjectWithTag("CameraShake").GetComponent<CameraShake>();
    }
    void LateUpdate()//随后触发
    {
        if (target != null)
        {
            if (transform.position != target.position)//实现跟随
            {
                Vector3 targetPos = target.position;
                targetPos.x = Mathf.Clamp(targetPos.x, minPosition.x, MaxPosition.x);
                targetPos.y = Mathf.Clamp(targetPos.y, minPosition.y, MaxPosition.y);
                transform.position = Vector3.Lerp(transform.position, targetPos, smoothing);
            }
        }
    }
    public void SetCamPosLimit(Vector2 minPos, Vector2 maxPos)
    {
        minPosition = minPos;
        MaxPosition = maxPos;
    }
}

(5) 公告板(Billboard)

   

//Sign(Script)
public class Sign : MonoBehaviour
{
    public GameObject dialogbox;//公告板
    private bool isPlayerInSign;//标记人物和公告板的碰撞
    // Start is called before the first frame update
    void Start()
    {
        dialogbox.SetActive(false);//设置公告信息不可见
    }
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.L) && isPlayerInSign) 
        {
            dialogbox.SetActive(true);//设置公告信息可见
        }
    }
    void OnTriggerEnter2D(Collider2D other)//检测碰撞 给isPlayerInSign赋值
void OnTriggerExit2D(Collider2D other)//离开碰撞体 设置公告信息不可见
//isPlayerInSign同步变化
}

(6) 游戏场景(Scene)

<项目源码>

JUNGLERULES_Unity工程文件.rar-其他文档类资源-CSDN下载

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐